package com.im.chat.websocket;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.im.chat.model.AuthUser;
import com.im.chat.model.ChatRecord;
import com.im.chat.model.ChatSession;
import com.im.chat.model.Member;
import com.im.chat.service.AuthUserService;
import com.im.chat.service.ChatRecordService;
import com.im.chat.service.ChatSessionService;
import com.im.chat.service.MemberService;
import com.im.chat.util.EmojiUtil;
import com.im.chat.websocket.dto.AdminStatusInfo;
import com.im.chat.websocket.dto.SendMsgDto;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * WebSocketServer
 * @author zhengkai.blog.csdn.net
 */
@ServerEndpoint("/imserver/{visitType}/{visitId}")
@Component
public class WebSocketServer {


    private static final Log LOGGER = LogFactory.getLog(WebSocketServer.class);


    public static WebSocketServer webSocketServer;

    @Autowired
    private ChatSessionService chatSessionService;
    @Autowired
    private ChatRecordService chatRecordService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private AuthUserService authUserService;

    @PostConstruct
    public void init(){
        webSocketServer = this;
        webSocketServer.chatSessionService = this.chatSessionService;
        webSocketServer.chatRecordService = this.chatRecordService;
        webSocketServer.memberService = this.memberService;
        webSocketServer.authUserService = this.authUserService;
    }

    /**静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。*/
    public static int onlineUserCount = 0;
    public static int onlineAdminCount = 0;
    /**concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。*/
    public static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();

    //TODO:用户状态
    public static ConcurrentHashMap<String, AdminStatusInfo> adminStatusMap = new ConcurrentHashMap<>();

    /**与某个客户端的连接会话，需要通过它来给客户端发送数据*/
    private Session session;
    /**接收visitId*/
    private String visitId="";
    private String visitType="";

    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session,@PathParam("visitType") String visitType,@PathParam("visitId") String visitId) {
        this.session = session;
        this.visitId= visitId;
        this.visitType= visitType;
        String visitTypeId = visitType + visitId;
        LOGGER.info("onOpen()------>visitId    "+visitId+",     visitType:"+visitType);
//        WebSocketServer  webSocketServer= (WebSocketServer) RedisCache.get("visitTypeId"); //||webSocketServer!=null
        if(webSocketMap.containsKey(visitTypeId)){//TODO:如果遇到相同用户登录连接，怎么处理？？？
            webSocketMap.remove(visitTypeId);
            webSocketMap.put(visitTypeId,this);
            LOGGER.info("user连接:"+visitTypeId+" 已经存在，重新建立连接");
        }else{
            webSocketMap.put(visitTypeId,this);
            LOGGER.info("user连接:"+visitTypeId+"建立连接");
            if(visitType.equals(WebSocketConstant.SENDER_TYPE_ADMIN)){
                AdminStatusInfo adminStatusInfo = new AdminStatusInfo();
                adminStatusInfo.setAdminId(Long.parseLong(visitId));
                adminStatusInfo.setOnlineStatus("on"); //在线状态enum
                adminStatusInfo.setUsernum(0);
                adminStatusMap.put(visitTypeId,adminStatusInfo);
            }

            //加入set中
            if(visitType.equals(WebSocketConstant.SENDER_TYPE_USER)){
                addOnlineUserCount();//user在线数加1
                LOGGER.info("user连接:"+visitTypeId+",当前在线人数为:" + getOnlineUserCount());
            }
            if(visitType.equals(WebSocketConstant.SENDER_TYPE_ADMIN)){
                addOnlineAdminCount();//admin在线数加1
                LOGGER.info("admin连接:"+visitTypeId+",当前在线人数为:" + getOnlineUserCount());
            }
        }
        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            LOGGER.error("用户:"+visitTypeId+",网络异常!!!!!!");
        }
    }



    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        String visitTypeId = this.visitType+this.visitId;
        LOGGER.info("onMessage()用户"+visitTypeId+",发送报文:");
        LOGGER.info(message);
        //可以群发消息,消息保存到数据库、redis????
        if(StringUtils.isNotBlank(message)){
            try {
                JSONObject jsonObject = JSON.parseObject(message);
                //TODO:追加发送人(防止串改)
                String toVisitTypeId = "";
                String fromVisitTypeId = "";
                SendMsgDto sendMsgDto=(SendMsgDto)JSONObject.toJavaObject(jsonObject, SendMsgDto.class);
                String msgUniqueCode = sendMsgDto.getMsgUniqueCode();
                String sendType = sendMsgDto.getSendType();
                String content = sendMsgDto.getContent();
                String contentType = sendMsgDto.getContentType();
                String fromVisitId = sendMsgDto.getFromVisitId();
                String toVisitId = sendMsgDto.getToVisitId();
                String chatId = sendMsgDto.getChatId();
                //String widthToHeight = sendMsgDto.getWidthToHeight();
                //String memberName = sendMsgDto.getMemberName();
                ChatRecord chatRecord = new ChatRecord();
                chatRecord.setMsgUniqueCode(msgUniqueCode);
                chatRecord.setContent(content);
                chatRecord.setContentType(Integer.parseInt(contentType));
                chatRecord.setSendType(Integer.parseInt(sendType));
                //chatRecord.setWidthToHeight(widthToHeight);

                ChatSession chatSession = null;
                if(sendType.equals("2")){   //发送人类型：1-user,2-admin
                    chatRecord.setAdminId(Long.parseLong(fromVisitId));
                    chatRecord.setMemberId(Long.parseLong(toVisitId));
                    toVisitTypeId = WebSocketConstant.SENDER_TYPE_USER + toVisitId;//memberId  即toVisitId
                    fromVisitTypeId = WebSocketConstant.SENDER_TYPE_ADMIN + fromVisitId;
                   // chatSession = webSocketServer.chatSessionService.getInfoByMemberId(chatRecord.getMemberId());
                    chatSession = webSocketServer.chatSessionService.getChatSessionByChatId(Long.parseLong(chatId));
                }

                if(sendType.equals("1")){   //发送人类型：1-user,2-admin
                    chatRecord.setMemberId(Long.parseLong(fromVisitId));
                    if(toVisitId!=null && !toVisitId.equals("")){
                        //chatSession = webSocketServer.chatSessionService.getInfoByMemberId(Long.parseLong(fromVisitId));
                        chatSession = webSocketServer.chatSessionService.getChatSessionByChatId(Long.parseLong(chatId));
                        toVisitId = String.valueOf(chatSession.getAdminId());
                        toVisitTypeId = WebSocketConstant.SENDER_TYPE_ADMIN + toVisitId;//adminId  即toVisitId
                        fromVisitTypeId = WebSocketConstant.SENDER_TYPE_USER + fromVisitId;

                        chatRecord.setAdminId(Long.parseLong(toVisitId));
                    }
                    else{
                        //chatSession = webSocketServer.chatSessionService.getInfoByMemberId(Long.parseLong(fromVisitId));
                        chatSession = webSocketServer.chatSessionService.getChatSessionByChatId(Long.parseLong(chatId));
                        if(chatSession!=null){//TODO:需要判断会话聊天状态。
                            Long adminId = chatSession.getAdminId();
                            toVisitTypeId = WebSocketConstant.SENDER_TYPE_ADMIN + adminId;//adminId  即toVisitId
                            fromVisitTypeId = WebSocketConstant.SENDER_TYPE_USER + fromVisitId;
                            chatRecord.setAdminId(adminId);
                            toVisitId = String.valueOf(adminId);
                        }else{
                            //创建会话聊天
                            System.out.println("创建会话聊天----->");
                        }
                    }
//                        else{
//                            //int totalAdminadmin = adminStatusMap.keySet().size();
//                            //TODO:选择一个adminId聊天  ？？？？
//                            int adminStatusSize = adminStatusMap.keySet().size();
//                            Random random = new Random();
//                            int num = random.nextInt(adminStatusSize);
//                            int i=0;
//                            for(String myvisitTypeId:adminStatusMap.keySet()){
//                                toVisitTypeId = myvisitTypeId;
//                                AdminStatusInfo adminStatusInfo = adminStatusMap.get(myvisitTypeId);
//                                chatRecord.setAdminId(adminStatusInfo.getAdminId());
//                                if(num==i){
//                                    break;
//                                }
//                                i++;
//                            }
//                            fromVisitTypeId = WebSocketConstant.SENDER_TYPE_USER + fromVisitId;
//                            //1.新建session会话信息
//                            chatSession = new ChatSession();
//                            chatSession.setAdminId(chatRecord.getAdminId());
//                            //toVisitId = String.valueOf(chatRecord.getAdminId());
//                            chatSession.setMemberId(chatRecord.getMemberId());
//                            Member member = webSocketServer.memberService.findById(chatRecord.getMemberId());
//                            AuthUser authUser = webSocketServer.authUserService.findById(chatRecord.getAdminId());
//                            if(member!=null){
//                                chatSession.setMemberName(member.getLoginName());//只存登录名
//                            }
//                            if(authUser!=null){
//                                chatSession.setAdminName(authUser.getLoginName());//只存登录名
//                            }
//
//
//                            chatSession.setStatus(WebSocketConstant.CHATSESSIOIN_STATUS_0);//0正常
//                            long newChatId =  webSocketServer.chatSessionService.insertChatSession(chatSession);
//                            if(newChatId==1){
//                                //chatSession =  webSocketServer.chatSessionService.getInfoByMemberId(chatSession.getMemberId());
//                                chatSession = webSocketServer.chatSessionService.getChatSessionByChatId(Long.parseLong(chatId));
//                                chatRecord.setChatId(chatSession.getId());
//                            }else{
//                                chatSession.setId(newChatId);
//                                chatRecord.setChatId(newChatId);
//                            }
//
//                            //admin_id不存在，则随机选一个在线的admin_id
//                            //在线admin_id的选择？ConcurrentHashMap<String,AdminStatusInfo> adminStatusMap
//                            //拿 在线的，会话，最少的人，的admin_id
//
//                        }
//                    }


                    }

                //判断拉黑状态
                if(chatSession.getStatus()!=1){//0:正常，1拉黑会话，2-关闭会话
                    this.updateSessionInfo(chatSession,chatRecord);
                    if(chatId.equals("")){
                        if (chatSession!=null){
                            jsonObject.put("chatId",chatSession.getId());
                        }
                    }
                    Member member = webSocketServer.memberService.findById(chatRecord.getMemberId());
                    AuthUser authUser = webSocketServer.authUserService.findById(chatRecord.getAdminId());
                    if(member!=null){
                        jsonObject.put("memberLoginName",member.getLoginName());
                    }
                    if(authUser!=null){
                        jsonObject.put("adminLoginName",authUser.getLoginName());
                    }

                    //TODO:修改content的内容（转换表情格式，图片拼接。）
                    jsonObject.put("content",EmojiUtil.transEmoji(content,jsonObject.get("content").toString()));
                    jsonObject.put("toVisitId",toVisitId);
                    LOGGER.info("onMessage()转发消息----->:"+toVisitTypeId);
                    if(StringUtils.isNotBlank(toVisitTypeId)&&webSocketMap.containsKey(toVisitTypeId)){
                        //给对方发送消息
                        LOGGER.info("给对方发送消息---onMessage()转发toVisitTypeId-->:"+toVisitTypeId);
                        LOGGER.info("给对方发送消息---onMessage()转发内容---jsonObject.toJSONString()-->:"+jsonObject.toJSONString());
                        webSocketMap.get(toVisitTypeId).sendMessage(jsonObject.toJSONString());
                    }else{
                        //TODO:给自己发送消息????
                        jsonObject.put("content","用户ID:"+toVisitTypeId+"不在线");
                        jsonObject.put("contentType","4");//系统提醒消息
                        LOGGER.info("给自己发送消息---onMessage()转发fromVisitTypeId-->:"+fromVisitTypeId);
                        LOGGER.info("给自己发送消息---onMessage()转发内容---jsonObject.toJSONString()-->:"+jsonObject.toJSONString());
                        webSocketMap.get(fromVisitTypeId).sendMessage(jsonObject.toJSONString());
                        LOGGER.info("请求的visitId:"+toVisitTypeId+"不在该服务器上");
                    }
                }else{
                    LOGGER.info("该用户  toVisitTypeId---->"+toVisitTypeId+"已被拉黑！！！ fromVisitTypeId--->"+fromVisitTypeId);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }


    public void updateSessionInfo(ChatSession chatSession,ChatRecord chatRecord){
        chatSession.setStatus(WebSocketConstant.CHATSESSIOIN_STATUS_0);//0正常
        webSocketServer.chatSessionService.updateById(chatSession);
        chatRecord.setChatId(chatSession.getId());
        webSocketServer.chatRecordService.add(chatRecord);
    }
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    /**
     * 发送自定义消息
     * */
    public static void sendInfo(String message,@PathParam("visitType") String visitType,@PathParam("visitId") String visitId) throws IOException {
        String visitTypeId = visitType+"_"+visitId;
        LOGGER.info("发送消息到:"+visitTypeId+"，报文:"+message);
        if(StringUtils.isNotBlank(visitId)&&webSocketMap.containsKey(visitTypeId)){
            webSocketMap.get(visitTypeId).sendMessage(message);
        }else{
            LOGGER.info("用户"+visitTypeId+",不在线！");
        }
    }
    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        LOGGER.info("用户错误:"+this.visitType+"_"+this.visitId+",原因:"+error.getMessage());
        error.printStackTrace();
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        String visitTypeId = this.visitType+"_"+this.visitId;
        LOGGER.info("onClose()---->user退出:"+visitTypeId);
        if(webSocketMap.containsKey(visitTypeId)){
            webSocketMap.remove(visitTypeId);
            //TODO:下线通知：？？？？
            //从set中删除
            if(visitType.equals(WebSocketConstant.SENDER_TYPE_USER)){
                subOnlineUserCount();
                LOGGER.info("onClose()---->user退出:"+visitTypeId+",当前在线人数为:" + getOnlineUserCount());
            }
            if(visitType.equals(WebSocketConstant.SENDER_TYPE_ADMIN)){
                subOnlineAdminCount();
                LOGGER.info("onClose()--->admin退出:"+visitTypeId+",当前在线人数为:" + getOnlineAdminCount());
            }

        }

    }

    public static synchronized int getOnlineUserCount() {
        return onlineUserCount;
    }

    public static synchronized void addOnlineUserCount() {
        WebSocketServer.onlineUserCount++;
    }

    public static synchronized void subOnlineUserCount() {
        WebSocketServer.onlineUserCount--;
    }


    public static synchronized int getOnlineAdminCount() {
        return onlineAdminCount;
    }

    public static synchronized void addOnlineAdminCount() {
        WebSocketServer.onlineAdminCount++;
    }

    public static synchronized void subOnlineAdminCount() {
        WebSocketServer.onlineAdminCount--;
    }

}